package loggers;

import java.util.Date;

import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemStateListener;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import javax.microedition.rms.RecordStore;

import util.KeyListeningItem;
import util.Preferences;
import util.Storage;
import connectionSettings.ConnectionSettings;
import connections.Connection;
import connections.Uploader;

//
public class Logger extends MIDlet implements ItemStateListener, CommandListener {

	public class IntervalometerThread extends Thread {

		boolean running = true;

		public void kill() {
			running = false;
		}

		public void run() {
			while (running) {
				try {
					requestData();
					Thread.sleep(interval);
				} catch (InterruptedException e) {
					System.out.println("Bad Sleep");
				}
			}

		}
	}

	ConnectionSettings connectionSettings;

	int currentRecord = -1;

	Storage dataStore;

	String inputName = "none";

	int interval = 1000;

	boolean updateDisplay  = true;

	long lastLogTime;
	
	String info;

	//TextField logInfo;
	TextField newName;
	TextField intervalField;

	String logName = "Default.log";

	ChoiceGroup logs;

	public Form mainForm;

	IntervalometerThread myIntervalometer;

	Uploader myUploader;



	String[] phonyData = { "ABCD", "EFGH", "IJKL", "MNOP", "QRST", "UVWX", "YZ" };

	int placeInPhonyData = 0;

	public Preferences prefs;

	KeyListeningItem recordInfo;

	int recordsAdded = 0;

	boolean timeStampEachRecord = true;

	ChoiceGroup timeStamping;

	int uploads = 0;

	boolean waitForTransmission;

	public void addALog(byte[] _bytes) {
		//dataStore.addRecord(_bytes);
		dataStore.addRecord(_bytes);
	//	mainForm.append(dataStore.getLastError());
		recordsAdded++;

	
		//currentRecord = 0; // 
		currentRecord = dataStore.getNumberOfRecords() - 1;

	}

	public void addALog(byte[] _bytes, byte[] _metadata) {
		dataStore.addRecord(_bytes, _metadata);
		// dataStore.addRecord(_bytes);
		recordsAdded++;

		//currentRecord = 0; //dataStore.getNumberOfRecords() - 1;
		currentRecord = dataStore.getNumberOfRecords() - 1;


	}

	public void setUploaderProtocol(Uploader _uploader) {

	}

	public void commandAction(Command c, Displayable d) {

		String menuChoice = c.getLabel();
		System.out.println("CommandAction " + menuChoice);
		if (menuChoice.equals("Start Logging")) {
			// mode = "Logging";
			setVariablesFromInterface();
			System.out.println("interval is" + interval);
			startLogging();

		} else if (menuChoice.equals("Stop Logging")) {
			stopLogging();

			// } else if (menuChoice.equals("Next Record")) {

			// } else if (menuChoice.equals("Previous Record")) {

		} else if (menuChoice.equals("Clear Log")) {
			dataStore.clearRecords();
			displayRecordStores();
			System.out.println("response" + dataStore.getLastError());
		} else if (menuChoice.equals("Delete Log")) {
			// Alert sure = new Alert("Are you sure");
			// sure.setString("Are you sure");

			// Display.getDisplay(this).setCurrent(sure);

			dataStore.done();
			dataStore.deleteMe();
			System.out.println("response" + dataStore.getLastError());
			displayRecordStores();
		} else if (menuChoice.equals("Choose Log")) {
			displayRecordStores();
		} else if (menuChoice.equals("Upload")) {

			myUploader = new Uploader(Display.getDisplay(this), dataStore);
			setUploaderProtocol(myUploader);
			// } else if (menuChoice.equals("Record Time Stamps")) {
			// timeStampEachRecord = !timeStampEachRecord;
			// dataStore.setTimeStamping(timeStampEachRecord);
			// if (timeStampEachRecord) {
			// display("All Records will be automatically time stamped");
			// } else {
			// display("Records will not be time stamped");
			// }
		} else if (menuChoice.equals("Ask For Input")) {
			requestData();
			// sensorConnection.send((byte) 13);

		}

		else if (menuChoice.equals("Add Phony Data")) {
			String pd = phonyData[placeInPhonyData];
			placeInPhonyData++;
			if (placeInPhonyData >= phonyData.length) placeInPhonyData = 0;
			addALog(pd.getBytes());
			displayInterface();
		} else if (menuChoice.indexOf("Preferences") != -1) {
			if (mainForm.get(0) == intervalField) {
				displayInterface();

			} else {
				displayPreferences(mainForm);
			}

		} else if (menuChoice.equals("Exit")) {
			System.out.println("Bye");
			// mainForm.append(interval);
			try {
				destroyApp(false);
			} catch (MIDletStateChangeException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			notifyDestroyed();

		}
	}

	protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
		// setVariablesFromInterface();
		// setPrefs();
		System.out.println("Destroy in Logger");
		takeDownSensorConnection();
		prefs.done();
		dataStore.done();
	}

	// public void setPrefs() {
	// setPrefs(logName, timeStampEachRecord, waitForTransmission, requestTransmission, interval);
	// }

	public void display(String _s) {
		mainForm.append(_s);
	}

	public void displayCurrentLog() {

		if (dataStore != null && updateDisplay == true) {
			// /mainForm.deleteAll();
			info = "";

			info = info + ("---Log Info---" + "\n");
			info = info + "CURRENT LOG: " + logName + "\n INPUT:" + inputName + "\n";
			long[] properties = Storage.getInfo(logName);
			String date = (new Date(properties[0])).toString();
			long percentFull = 100*properties[2]/properties[3];
			info = info + (properties[2] + " bytes " + percentFull +  "% \n") ;
			info = info + date + "\n\n";

			info = info + ("---Record Info---" + "\n");
			recordInfo.setString(info);
			// logInfo.setString(info);
			
		
			long numRecords = properties[1];
	
			if (numRecords > 0) {
				
				// if (currentRecord != -1 && currentRecord < numRecords) {
				// System.out.println("Current Record " + currentRecord);
				byte[] rec = dataStore.getRecord(currentRecord);
			
				String rdate = "";
				if (dataStore.isTimeSTamping()) rdate = (new Date(dataStore.getTimeStamp(currentRecord))).toString();
				info = info + ((currentRecord + 1) + " of " + numRecords + "    (Press <4 6>) \n" + rdate + "\n");
			
				info = info + (recordsAdded + " added this session \n");
				//System.out.println(currentRecord + "seting info" + new String(rec) );
				displayRecord(rec);
				recordInfo.setString(info);
		
			} else {
				info = info + ("NoRecords");
				recordInfo.setString(info);
			}
			

			// }
		}

	}

	public void displayInterface() {
		//if (mainForm.size() == 0 || mainForm.get(0) != recordInfo) {
		mainForm.deleteAll();
		// mainForm.append(logInfo);
		mainForm.append(recordInfo);
		//System.out.println("ADDED TO FORM");
		displayCurrentLog();
		//}
	}

	public void displayMenu() {

		Command startLogging = new Command("Start Logging", Command.OK, 1);
		Command stopLogging = new Command("Stop Logging", Command.OK, 2);
		Command upload = new Command("Upload", Command.OK, 3);
		Command chooseLog = new Command("Choose Log", Command.OK, 4);
		// Command nextRecord = new Command("Next Record", Command.OK, 5);
		// Command previousRecord = new Command("Previous Record", Command.OK, 6);
		Command deleteLog = new Command("Delete Log", Command.OK, 7);
		Command clearLog = new Command("Clear Log", Command.OK, 8);
		Command askForInput = new Command("Ask For Input", Command.OK, 9);
		Command setPreferences = new Command("Hide/Show Preferences", Command.OK, 10);
		Command addPhony = new Command("Add Phony Data", Command.OK, 11);
		Command exit = new Command("Exit", Command.OK, 12);

		mainForm.addCommand(startLogging);
		mainForm.addCommand(stopLogging);
		mainForm.addCommand(upload);
		mainForm.addCommand(chooseLog);
		// mainForm.addCommand(nextRecord);
		// mainForm.addCommand(previousRecord);
		mainForm.addCommand(deleteLog);
		mainForm.addCommand(clearLog);
		mainForm.addCommand(askForInput);
		mainForm.addCommand(setPreferences);
		mainForm.addCommand(addPhony);
		mainForm.addCommand(exit);

	}

	// public void setInterval(){
	// mainForm.append(intervalFie);
	// }
	public void displayPreferences(Form _mainForm) {

		setInterfaceFromVariables();
		_mainForm.deleteAll();
		_mainForm.append(intervalField);
		_mainForm.append(timeStamping);

		// _mainForm.append(pacing);

	}

	public void displayRecord(byte[] _bytes) {

		//String info = "";
		// info = info + ("<4 prev next 6> Record: " + (currentRecord + 1) + " of " + dataStore.getNumberOfRecords() + "\n");
	
		if (_bytes == null) {
			info = info + ("This Record is Empty");

		} else if (_bytes.length < 255) {
			//System.out.println("Display Record" + new String(_bytes));
			info = info + ("Contents: " + new String(_bytes) );
		} else {
			info = info + (_bytes.length + "Size of this Record" );
		}
		//Connection c = connectionSettings.getConnection();
		//c != null  && c.isListening() &&
		//if ( getInterval() > 0) {
		//	info = info + (getInterval() / 1000) + " secs Next Recording.\n";
		//}
		//recordInfo.setString(info);
		//recordInfo.addString(info);

	}

	public void displayRecordStores() {
		mainForm.deleteAll();
		mainForm.append("PICK CURRENT LOG");
		logs.deleteAll();
		logs.append("Create New Log", null);
		// databases.append("La", null);
		newName.setString("blank");
		mainForm.append(newName);
		mainForm.append(logs);
		String[] names = RecordStore.listRecordStores();
		if (names != null) {
			for (int i = 0; i < names.length; i++) {
				// (names[i].toLowerCase().indexOf("log") != -1) {
				if (names[i].toLowerCase().endsWith(".log")) {
					long[] info = Storage.getInfo(names[i]);
					String date = (new Date(info[0])).toString();
					logs.append(names[i] + " " + info[1] + " " + info[2] + "b\n" + date, null);
				}
			}
		}

	}

	public byte[] formatSensorData(byte[] _input) {
		return _input;
		// String inputAsString = new String(_input);
		// String timeStamp = String.valueOf(System.currentTimeMillis());
		// return (timeStamp + "," + inputAsString).getBytes();
	}

	public long getInterval() {
	//	System.out.println("hey" + interval);
		return interval;
	}

	public void getPrefs() {
		// Storage prefs = new Storage(this.getClass().getName() + ".prefs");
		String s = prefs.getPref("logName");
		if (s != null) logName = s;
		s = prefs.getPref("timeStampEachRecord");
		if (s != null) timeStampEachRecord = s.equals("true");
		// s = prefs.getPref("waitForTransmission");
		// if (s != null) waitForTransmission = s.equals("true");
		// s = prefs.getPref("requestTransmission");
		// if (s != null) requestTransmission = s.equals("true");
		s = prefs.getPref("interval");
		if (s != null) interval = Integer.parseInt(s);
		// System.out.println("Getting" + s);
	}

	public void inputFromSensor(byte[] _input) {
		long now = System.currentTimeMillis();
		if (now - lastLogTime > getInterval()) { // if it is spewing and you just want to record a few
			lastLogTime = now;
			addALog(formatSensorData(_input));
		
			// sensorConnection.clearInput();
			// requestData();
			displayCurrentLog();
		}
	}

	public void itemStateChanged(Item thisItem) {

		// System.out.println("ItemStageChanged " + thisItem);
		if (thisItem == logs) {

			int choiceNum = ConnectionSettings.getFirstOfMultiple(logs);
			if (choiceNum != -1) {
				logName = logs.getString(choiceNum);
			}
			// databaseName = databases.getString(databases.getSelectedIndex());

			if (logName.equals("Create New Log")) {
				if (newName.getString().toLowerCase().indexOf(".log") == -1) {
					logName = newName.getString() + ".log";
				} else {
					logName = newName.getString();
				}
			} else {
				int space = logName.indexOf(" ");
				logName = logName.substring(0, space);
			}
			dataStore = new Storage(logName);
			dataStore.setTimeStamping(timeStampEachRecord);
			// mainForm.deleteAll();
			displayInterface();

			setPrefs();
		} else if (thisItem == recordInfo) {

			System.out.println("logger record change");
			String command = recordInfo.getLastCommand();
			if (command.equals("Right")) {
				int numRecords = dataStore.getNumberOfRecords();
				System.out.println("next");
				if (dataStore != null && numRecords > 0) {

					currentRecord++;
					if (currentRecord >= numRecords) currentRecord = 0;
					displayCurrentLog();
				}
			} else if (command.equals("Left")) {
				System.out.println("previous");
				int numRecords = dataStore.getNumberOfRecords();
				if (dataStore != null && numRecords > 0) {
					currentRecord--;
					if (currentRecord < 0) currentRecord = numRecords - 1;
					displayCurrentLog();
				}
			} else if (command.equals("9")) {
				updateDisplay = ! updateDisplay ;
			}

		} else {
			// preferences

			setVariablesFromInterface();
			setPrefs();
		}

	}

	protected void pauseApp() {

	}

	public void requestData() {
		// sensorConnection.clearInput();
		Connection c = connectionSettings.getConnection();
		if (c != null  && c.isListening()) {

			c.send((byte) connectionSettings.getRequestChar());
			// System.out.println("Requested" + connectionSettings.getRequestChar());
		}
	}

	public void setInputName(String _name) {
		inputName = _name;
	}

	public void setInterfaceFromVariables() {
		// reflect it in the interface
		boolean[] tsFlags = { timeStampEachRecord, !timeStampEachRecord };

		timeStamping.setSelectedFlags(tsFlags);

		intervalField.setString(String.valueOf(interval));

		// boolean[] flags = { waitForTransmission};

		// pacing.setSelectedFlags(flags);

	}

	public void setInterval(long _interval) {
		interval = (int) _interval;
	}

	// public void setPrefs(String _logName, boolean _timeStampEachRecord, boolean _waitForTransmission, boolean _requestTransmission, int _interval) {
	public void setPrefs() {
		// set the variables
		prefs.setPref("logName", logName);
		prefs.setPref("timeStampEachRecord", timeStampEachRecord);
		prefs.setPref("interval", interval);
		prefs.savePrefs();
	}

	public void setUpSensorConnection() {
		if (connectionSettings.isNeedToRequestData()) {
			startIntervalometer();
		}
	}
	
	public void takeDownSensorConnection(){
		
	}

	public void setVariablesFromInterface() {
		boolean[] tschecks = new boolean[timeStamping.size()]; // _recentChoices.size()]; // have to go through this because I used "MULTIPLE"
		timeStamping.getSelectedFlags(tschecks);
		timeStampEachRecord = tschecks[0];

		// boolean[] checks = new boolean[pacing.size()]; // _recentChoices.size()]; // have to go through this because I used "MULTIPLE"
		// pacing.getSelectedFlags(checks);
		// waitForTransmission = checks[0];
		// requestTransmission = checks[1];

		// if (waitForTransmission) {
		// intervalField.setLabel("Interval Between Recording");
		// requestCharField.setLabel("Request Char (NA)");
		// } else {
		// intervalField.setLabel("Interval Between Requests");
		// requestCharField.setLabel("Request Char");
		// }
		try {
			interval = Integer.parseInt(intervalField.getString());
		} catch (NumberFormatException e) {
			System.out.println("Not a Number");
		}
		//
	}

	public void startApp() throws MIDletStateChangeException {
		mainForm = new Form("Main");

		// mainForm.append("Pick a Log.");
		// choices = new ChoiceGroup("Pick One", ChoiceGroup.MULTIPLE);
		logs = new ChoiceGroup("Logs", ChoiceGroup.MULTIPLE);
		newName = new TextField("New name for log:", null, 32, TextField.ANY);
		//logInfo = new TextField("", null, 255, TextField.ANY | TextField.UNEDITABLE);
		// int h = logInfo.getPreferredHeight();
		//int w = logInfo.getPreferredWidth();
		recordInfo = new KeyListeningItem("");

		//recordInfo.setPreferredSize(100, 500);
		recordInfo.setItemStateListener(this);
		// recordInfo = new TextField("Record Info:", null, 255,TextField.ANY | TextField.UNEDITABLE);
		intervalField = new TextField("Sample Interval (ms):", null, 5, TextField.DECIMAL);

		timeStamping = new ChoiceGroup("Time Stamp Each Record", ChoiceGroup.EXCLUSIVE);
		timeStamping.append("Yes", null);
		timeStamping.append("No", null);
		prefs = new Preferences(this.getClass().getName() + ".prefs");

		Display.getDisplay(this).setCurrent(mainForm);
		displayMenu();
		getPrefs();
		setInterfaceFromVariables();
		// setPrefs();
		dataStore = new Storage(logName);
		
		dataStore.setTimeStamping(timeStampEachRecord);
		mainForm.append(dataStore.getLastError());
		if (dataStore.getNumberOfRecords() > 0) currentRecord = 0;
		// displayRecordStores();
		mainForm.setItemStateListener(this);
		mainForm.setCommandListener(this);

		displayInterface();

		// setInterfaceFromVariables();
	}

	public void startIntervalometer() {
		long iv = getInterval();
	//	System.out.println("start interval" + iv);
		if (iv > 0) {
			myIntervalometer = new IntervalometerThread();
			myIntervalometer.start();
		}
	}

	public void startIntervalometer(long _interval) {
		System.out.println("Start Intervalometer");
		if (_interval != -1) {
			setInterval(_interval);
		}
		myIntervalometer = new IntervalometerThread();
		myIntervalometer.start();
	}

	public void startLogging() {

	}

	public void stopIntervalometer() {
		if (myIntervalometer != null) myIntervalometer.kill();
	}

	public void stopLogging() {

	}

}
/*
 * public byte[] joinLogs(String _delim) { String output = ""; int[] allRecordIDs = dataStore.getRecordIDs(); for (int i = 0; i < allRecordIDs.length; i++) { byte[] thisRecord = (byte[]) dataStore.getRecord(allRecordIDs[i]); if (_delim == null) { output = output + _delim + new String(thisRecord); } else { output = output + new String(thisRecord); }
 * 
 * try { Thread.sleep(80); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return output.getBytes(); }
 */